package org.github.manx98.jlibhac.tools.fssystem.romfs;

import org.github.manx98.jlibhac.fs.IStorage;

import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * @author Manx98
 * @version 1.0
 * @since 2022/10/4 23:24
 */
public class HierarchicalRomFileTable {
    private final RomFsDictionary<FileRomEntry> fileTable;
    private final RomFsDictionary<DirectoryRomEntry> directoryTable;

    public HierarchicalRomFileTable(IStorage dirHashTable, IStorage dirEntryTable, IStorage fileHashTable, IStorage fileEntryTable) throws IOException {
        this.fileTable = new RomFsDictionary<FileRomEntry>(fileHashTable, fileEntryTable, FileRomEntry.class);
        this.directoryTable = new RomFsDictionary<DirectoryRomEntry>(dirHashTable, dirEntryTable, DirectoryRomEntry.class);
    }

    public FindPosition tryOpenDirectory(String path) throws IOException {
        RomEntryKey key = findPathRecursive(path);
        RomFsDictionary.EntryReferenceResult<DirectoryRomEntry> result = directoryTable.tryGetValue(key);
        if (result == null) {
            throw new FileNotFoundException("Not found directory: " + path);
        }
        DirectoryRomEntry directoryRomEntry = result.entry.Value;
        return directoryRomEntry.Pos;
    }

    private RomEntryKey findPathRecursive(String path) throws IOException {
        int index = 0;
        String[] split = path.split("/");
        if (split.length == 0) {
            return new RomEntryKey("", 0);
        }
        RomEntryKey key = new RomEntryKey(split[index], index);
        while (index < split.length - 1) {
            key.Parent = directoryTable.getOffsetFromKey(key);
            index++;
            if (index < split.length) {
                key.Name = split[index];
            }
        }
        return key;
    }

    public String findNextDirectory(FindPosition position) {
        RomFsEntry<DirectoryRomEntry> entry = new RomFsEntry<>();
        String nextDirectory = findNextDirectory(position, entry);
        if (nextDirectory == null) {
            return null;
        }
        position.NextDirectory = entry.Value.NextSibling;
        return nextDirectory;
    }

    public String findNextDirectory(FindPosition position, RomFsEntry<DirectoryRomEntry> entry) {
        if (position.NextDirectory == -1) {
            return null;
        }
        return directoryTable.getValueReference(position.NextDirectory, entry);
    }

    public RomFileInfo tryOpenFile(String filePath) throws IOException {
        RomEntryKey key = findPathRecursive(filePath);
        RomFsDictionary.EntryReferenceResult<FileRomEntry> result = fileTable.tryGetValue(key);
        return result.entry.Value.Info;
    }

    public RomFsDictionary.EntryReferenceResult<FileRomEntry> findNextFile(FindPosition position) throws IOException {
        if (position.NextFile == -1) {
            return null;
        }
        RomFsDictionary.EntryReferenceResult<FileRomEntry> entryReference = fileTable.getEntryReference(position.NextFile);
        position.NextFile = entryReference.entry.Value.NextSibling;
        return entryReference;
    }
}
